package core;

import graphics.ImageHandler;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.geom.GeneralPath;
import java.util.Vector;

import core.actions.Action;

public class V2SpinnerGraphics {
	
	final static int size=120, innerMarginal=5, iSize=15, barSize=10, barArcSize=70, extraHLight=20, extraHLightWidth=5;

	final static double PI = 3.1415;
	
	private V2Spinner sp;
	private Player master;
	private int x,y, depth;
	
	private Color primaryC, secondaryC, highlightC;
	
	
	/**
	 * id 0 is outer rightmost action, spiral clockwise.
	 * action x, y = x+y*radius
	 */
	private Vector<GeneralPath> actionPaths = new Vector<GeneralPath>();
	private Point[][] actionCenters = new Point[5][5];
	private int depthIncPx=30;
	
	
	protected V2SpinnerGraphics(V2Spinner s){
		sp=s;
		master=sp.master;
		primaryC=master.getColor();
		secondaryC=new Color((primaryC.getRed()+255)/2, (primaryC.getGreen()+255)/2, (primaryC.getBlue()+255)/2);
		setDefaultPosition();
		generatePaths();
	}
	protected V2SpinnerGraphics(V2Spinner s, Color c){
		sp=s;
		master=sp.master;
		primaryC=c;
		secondaryC=new Color((primaryC.getRed()+255)/2, (primaryC.getGreen()+255)/2, (primaryC.getBlue()+255)/2);
		setDefaultPosition();
		generatePaths();
	}
	private void setDefaultPosition(){
		if(master != null){
			x=master.getX();
			y=master.getY();
		}
		else{
			x=0;
			y=0;
		}
	}
	public void paint(Graphics g) {
		
		if(master!=null)
			drawBars(g);
		/*drawBaseOval(g);	

    	highlightCurrentOption(g);
    	drawActionIcons(g);*/
    	drawPlayerKey(g);
    	
    	
    	drawPaths(g);
    	
    	//draws pointerline    	
    	g.setColor(Color.black);
    	g.drawLine(x, y, (int)(x+Math.cos(sp.optionDir*3.1415*2)*size/2), (int)(y+Math.sin(sp.optionDir*3.1415*2)*size/2));
    	
	}
	private void drawBaseOval(Graphics g){
		g.setColor(primaryC);
    	g.fillOval(x-size/2, y-size/2, size, size);
    	g.setColor(Color.black);
    	depth=sp.actions.getDepth();
    	for(int c=1; c<=depth; c++){
    		g.drawOval(x-size/depth*c/2, y-size/depth*c/2, size/depth*c, size/depth*c);
    	}
    	for(int c=0; c<sp.actions.getRadius(); c++){
			int roundX = (int)(x+Math.cos((double)c/sp.actions.getRadius()*PI*2)*size/2);
			int roundY = (int)(y+Math.sin((double)c/sp.actions.getRadius()*PI*2)*size/2);
			g.drawLine(x, y, roundX, roundY);
    	}
	}	
	private void drawActionIcons(Graphics g){
		int iconSize = size/depth/2;
		for(int p=0; p<sp.actions.getRadius(); p++){
			for(int d=0; d<depth; d++){
				if(sp.actions.getActionAcceptNull(p, d)!=null){
					g.setColor(Color.black);
					int corX = (int)(x+Math.cos((double)p/sp.actions.getRadius()*PI*2+PI/sp.actions.getRadius())*size*((depth-d-1)*2+1)/(depth)/4)-iconSize/2; //topleft x
					int corY = (int)(y+Math.sin((double)p/sp.actions.getRadius()*PI*2+PI/sp.actions.getRadius())*size*((depth-d-1)*2+1)/(depth)/4)-iconSize/2; //topleft y
					/*g.drawRect(corX,corY,iSize,iSize);
					g.setColor(Color.black);
					g.setFont(new Font("SANS_SERIF", Font.PLAIN, iSize-2));
					char cha=sp.actions.getActionAcceptNull(p, d).getChar();
					
					g.drawString(cha+"", corX+iSize/8, corY+iSize-1);*/
					String s = sp.actions.getActionAcceptNull(p, d).getImageName();
					ImageHandler.getInstance().drawImage(corX, corY, iconSize, iconSize, s, g);
				}
			}
		}
	}
	private void highlightCurrentOption(Graphics g){
		g.setColor(secondaryC);
		int startC = size/depth*(depth-sp.currentDepth-1);
		int endC = (size+extraHLightWidth)/depth*(depth-sp.currentDepth);
		for(int c=startC; c<endC; c++)
			g.drawArc(x-c/2, y-c/2, c, c, -360*sp.currentOption/sp.actions.getRadius()+extraHLight/2, -360/sp.actions.getRadius()-extraHLight);
		g.setColor(Color.blue);
		g.drawArc(x-startC/2, y-startC/2, startC, startC, -360*sp.currentOption/sp.actions.getRadius()+extraHLight/2, -360/sp.actions.getRadius()-extraHLight);
		g.drawArc(x-endC/2, y-endC/2, endC, endC, -360*sp.currentOption/sp.actions.getRadius()+extraHLight/2, -360/sp.actions.getRadius()-extraHLight);
		int dx=(int)(Math.cos((double)sp.currentOption/sp.actions.getRadius()*PI*2-extraHLight*PI/360) * size/depth/2);
		int dy=(int)(Math.sin((double)sp.currentOption/sp.actions.getRadius()*PI*2-extraHLight*PI/360) * size/depth/2);
		g.drawLine(x+dx*(depth-sp.currentDepth), y+dy*(depth-sp.currentDepth), x+dx*(depth-sp.currentDepth-1), y+dy*(depth-sp.currentDepth-1));
		dx=(int)(Math.cos((double)(sp.currentOption+1)/sp.actions.getRadius()*PI*2+extraHLight*PI/360) * size/depth/2);
		dy=(int)(Math.sin((double)(sp.currentOption+1)/sp.actions.getRadius()*PI*2+extraHLight*PI/360) * size/depth/2);
		g.drawLine(x+dx*(depth-sp.currentDepth), y+dy*(depth-sp.currentDepth), x+dx*(depth-sp.currentDepth-1), y+dy*(depth-sp.currentDepth-1));
	
		
	
	}
	
	/**
	 * Reworks the paths in actionPaths
	 * id 0 is outer rightmost action, spiral clockwise.
	 * action x, y = x+y*radius
	 */
	public void generatePaths(){
		int actionRad = sp.actions.getRadius();
		int actionDepth = sp.actions.getDepth();
		int resMult = 1;
		if(actionRad <=6){
			resMult=2;
		}
		float[][][] inner = new float[actionRad*resMult][actionDepth+1][2];
		float[][][] outer = new float[actionRad*resMult][actionDepth+1][2];
		
		actionCenters = new Point[actionRad][actionDepth];
		
		int centerSize = 30;
		depthIncPx=(int)(size/(actionDepth+0.5)/2);
		for(int d=0; d<actionDepth+1; d++){
			double dir = 0;
			double smallDirInc = PI/actionRad/resMult;
			int pixelRad = (int)(size/2-depthIncPx*d);
			int iconRad = pixelRad-depthIncPx/2;
			for(int i=0; i<actionRad*resMult; i++){				
				inner[i][d][0] = x+(float)(Math.cos(dir) * pixelRad);
				inner[i][d][1] = y+(float)(Math.sin(dir) * pixelRad);	
				dir = dir+smallDirInc*2;
				if(d != actionDepth && resMult==2 && i%resMult == 0){
					int iconX = x+(int)(Math.cos(dir) * iconRad);
					int iconY = y+(int)(Math.sin(dir) * iconRad);
					actionCenters[i/resMult][d] = new Point(iconX, iconY);
				}
			}
			
			pixelRad = (int)(pixelRad/Math.cos(smallDirInc));
			
			dir=smallDirInc;
			for(int i=0; i<actionRad*resMult; i++){
				outer[i][d][0] = x+(float)(Math.cos(dir) * pixelRad);
				outer[i][d][1] = y+(float)(Math.sin(dir) * pixelRad);
				if(d != actionDepth && resMult==1){
					int iconX = x+(int)(Math.cos(dir) * iconRad);
					int iconY = y+(int)(Math.sin(dir) * iconRad);
					actionCenters[i/resMult][d] = new Point(iconX, iconY);
				}
				

				dir = dir+smallDirInc*2;
			}
		}
	
		
		actionPaths.clear();				
		GeneralPath p = new GeneralPath();
		
		int r = actionRad*resMult;
		for(int d=0; d<actionDepth; d++){
			for(int i=0; i<actionRad; i++){
				p = new GeneralPath();
				if(resMult == 1){
					p.moveTo(inner[i][d][0], inner[i][d][1]);
					p.quadTo(outer[i][d][0], outer[i][d][1], inner[(i+1)%r][d][0], inner[(i+1)%r][d][1]);
					p.lineTo(inner[(i+1)%r][d+1][0], inner[(i+1)%r][d+1][1]);
					p.quadTo(outer[i][d+1][0], outer[i][d+1][1], inner[i][d+1][0], inner[i][d+1][1]);
				}
				else if(resMult == 2){
					p.moveTo(inner[i*resMult][d][0], inner[i*resMult][d][1]);
					p.quadTo(outer[i*resMult][d][0], outer[i*resMult][d][1], inner[(i*resMult+1)%r][d][0], inner[(i*resMult+1)%r][d][1]);
					p.quadTo(outer[i*resMult+1][d][0], outer[i*resMult+1][d][1], inner[(i*resMult+2)%r][d][0], inner[(i*resMult+2)%r][d][1]);
					
					p.lineTo(inner[(i*resMult+2)%r][d+1][0], inner[(i*resMult+2)%r][d+1][1]);
					p.quadTo(outer[i*resMult+1][d+1][0], outer[i*resMult+1][d+1][1], inner[(i*resMult+1)%r][d+1][0], inner[(i*resMult+1)%r][d+1][1]);
					p.quadTo(outer[i*resMult][d+1][0], outer[i*resMult][d+1][1], inner[i*resMult][d+1][0], inner[i*resMult][d+1][1]);
				}

				p.closePath();
				actionPaths.add(p);
			}
		}
		//Center
		p = new GeneralPath();
		p.moveTo(inner[0][actionDepth][0], inner[0][actionDepth][1]);
		for(int i=0; i<actionRad*resMult; i++){
			p.quadTo(outer[i][actionDepth][0], outer[i][actionDepth][1], inner[(i+1)%r][actionDepth][0], inner[(i+1)%r][actionDepth][1]);
		}
		p.closePath();
		actionPaths.add(p);
	}
	
	private void drawPaths(Graphics g){
		Graphics2D g2d = (Graphics2D)g;
		GeneralPath path = new GeneralPath();
		
		Stroke strokeSave = g2d.getStroke();               
        g.setColor(Color.YELLOW);
        g2d.setStroke(new BasicStroke(3));
        
        //generatePaths();

        
        int actionRad = sp.actions.getRadius();
		int actionDepth = sp.actions.getDepth();
		int ad=0, ar=0;
        int red = 0;
        int pathNo = 0;
        for(GeneralPath p : actionPaths){
        	ar=pathNo%actionRad;
        	ad=pathNo/actionRad;
        	Action a = sp.actions.getActionAcceptNull(ar, ad);
        	Color col=Color.magenta;
        	if (a!=null){
        		col=a.getColor();
        	}
        		
        	red = red+35;
        	if(sp.currentOption==ar && sp.currentDepth==ad)
        		col=secondaryC;
        		//col=Color.white;
        	if(sp.currentDepth==actionDepth && sp.currentDepth==ad)
        		col=secondaryC;
        		//col=Color.white;
        	g.setColor(col);
        	g2d.fill(p);
        	g.setColor(Color.black);
        	g2d.draw(p);
        	
        	if(ad < actionDepth){
        		//g2d.fillRect(actionCenters[ar][ad].x, actionCenters[pathNo%actionRad][pathNo/actionRad].y, 3, 3);
        		drawIcon(ar, ad, g);
        	}
        	else{
        		//g2d.fillRect(x, y, 3, 3);
        		drawIcon(ar, ad, g);
        	}
        	
        	pathNo++;
        }
        g2d.setStroke(strokeSave);
        
        highlightPath(sp.currentOption, sp.currentDepth, g);
        
	}
	private void highlightPath(int ar, int ad, Graphics g){
		Graphics2D g2d = (Graphics2D)g;
		
		Stroke strokeSave = g2d.getStroke();               
        g.setColor(Color.YELLOW);
        g2d.setStroke(new BasicStroke(8));
        
        int pathId = ar+ad*sp.actions.getRadius();
        if(pathId>=actionPaths.size())
        	pathId = actionPaths.size()-1;
		
		g.setColor(Color.blue);
    	g2d.draw(actionPaths.get(pathId));
    	g2d.setStroke(strokeSave);
	}
	private void drawIcon(int ar, int ad, Graphics g){
		if(sp.actions.getActionAcceptNull(ar, ad)!=null && ad < sp.actions.getDepth()){
			g.setColor(Color.black);
			int corX = actionCenters[ar][ad].x-depthIncPx/2;
			int corY = actionCenters[ar][ad].y-depthIncPx/2;

			String s = sp.actions.getActionAcceptNull(ar, ad).getImageName();
			ImageHandler.getInstance().drawImage(corX, corY, depthIncPx, depthIncPx, s, g);
		}
		if(sp.actions.getActionAcceptNull(ar, ad)!=null && ad >= sp.actions.getDepth()){
			int corX = x-depthIncPx/2;
			int corY = y-depthIncPx/2;

			String s = sp.actions.getActionAcceptNull(ar, ad).getImageName();
			ImageHandler.getInstance().drawImage(corX, corY, depthIncPx, depthIncPx, s, g);
			//g.fillRect(x, y, 6, 6);
		}
	}
	
	private void drawBars(Graphics g){
		g.setColor(Color.blue);
		g.fillArc(x-size/2-barSize, y-size/2-barSize, size+2*barSize, size+2*barSize, -barArcSize/2, (int)(barArcSize*master.getPercentEnergy()));
	}
	private void drawPlayerKey(Graphics g){
		if(master != null){
			g.setColor(primaryC);
			g.fillOval(x-size*3/5, y-size*3/5, size*2/5, size*2/5);
			g.setColor(Color.black);
			g.fillOval(x-size/2, y-size/2, 23, 23);
			g.setColor(Color.white);
			char key = master.getKey();
			g.drawString((""+key).toUpperCase(), x-size/2+6, y-size/2+16);
		}
	}
	public void setPosition(Point p){
		x=p.x;
		y=p.y;
		generatePaths();
	}
}
